﻿#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>




//• 操作符的分类：
//• 算术操作符： + 、 - 、 * 、 / 、 %
//• 移位操作符 :  << >> 
//• 位操作符 :  & | ^ 
//• 赋值操作符 :  = 、 += 、 -= 、 *= 、 /= 、 %= 、 <<= 、 >>= 、 &= 、 |= 、 ^= 
//• 单⽬操作符： ！、++、--、 & 、 * 、 + 、 - 、~、sizeof、(类型)
//• 关系操作符 :  > 、 >= 、 < 、 <= 、 == 、 != 
//• 逻辑操作符： && 、 ||
//• 条件操作符： ? :
//• 逗号表达式：,
//• 下标引⽤：[]
//• 函数调⽤：()
//• 结构成员访问：.、->



//二进制和进制转换
//int main()
//{
//	十进制 0~9
//	二进制 0~1
//	八进制 0~7
//	十六进制 0~15
//
//	/*十进制 ——> 二进制*/ //不停地 %2 取余，余数的颠倒顺序即是二进制
//	十进制：15
//	二进制：1111
//	printf("%d\n", 1111);
//	/*二进制转换为十进制*/  //如1111  从右边开始权重为2^0 2^1 2^2 2^3... 
//	以此类推，1111 就是(2^0) * 1 + (2^1) * 1 + (2^2) * 1 + (2^3) * 1 
//
//
//	/*二进制转换为八进制*/ 
//	我们知道  八进制 0~7 
//	7的二进制位数为 111 所以二进制位转换为八进制时最高只需3位
//	如一个二进制数为1111 -->  001 111  001二进制为1 111二进制为7
//	所以该二进制转换为八进制是 017 ---在17前加0表示为八进制，这是编译器规定的，不然编译器无法分辨17为
//	十进制还是八进制
//	printf("%d\n", 17); //17
//	printf("%d\n", 017);//15
//
//	/*二进制转换为十六进制*/
//	同样的 十六进制0~15
//	15的二进制数为 1111 所以最高只需4位
//	但是我们知道十六进制有十六个数字，为了防止误解
//	0~9   a  b  c  d  e  f
//	     10 11 12 13 14 15
//	转换方式与八进制相同，表示十六进制前需要加0x;
//	printf("%d\n", 16); //16
//	printf("%d\n", 0x16);//22
//
//	八进制和十六进制转换为二进制反推即可。
//
//	return 0;
//}


//原码 反码 补码 - 进行整数运算时才使用
//int main()
//{
//	整数的二进制表示方法有三种即 -> 原码 反码 补码
//	符号则由最高位表示符号位，其他表示数值位。
//	符号位0表示正数，1表示负数
//
//	整数类型是4字节->32个bit位的
//	00000000000000000000000000001010 -原码
//	int a = 10;
//	10000000000000000000000000001010 -原码
//	int b = -10;
//
//	正整数的原码 反码 补码相同
//
//	int a = 10;
//	00000000000000000000000000001010 -原码
//	00000000000000000000000000001010 -反码
//	00000000000000000000000000001010 -补码
//
//	负整数
//	/*原码：直接将数值按照正负数的形式翻译成⼆进制得到的就是原码。
//	反码：将原码的符号位不变，其他位依次按位取反就可以得到反码。
//	补码：反码 + 1就得到补码。
//	反码得到原码也是可以使⽤：取反， + 1的操作。*/
//
//	int b = 10;
//	10000000000000000000000000001010 -原码
//	11111111111111111111111111110101 -反码
//	11111111111111111111111111110110 -补码
//	
//	了解以上后，为什么要使用原码，反码，补码呢，原因是计算机系统中数据存放在内存中是
//	采用补码的形式，gpu中只有加法器，不可以算减法
//
//	如  1-1 这个是不能计算的       1+（-1）这个可以计算
//	printf("%d", 1 + (- 1)); //答案毋庸置疑是0
//	但是需要使用补码来计算
//	 1的原码：00000000000000000000000000000001 -原码
//	-1的原码：10000000000000000000000000000001 -原码
//	 相加则为 10000000000000000000000000000010 - 这个答案是-2 则计算错误
//
//
//	但是使用补码计算就是对的
//	 1的补码：00000000000000000000000000000001 -补码
//	-1的补码：11111111111111111111111111111111 -补码
//	相加则为：100000000000000000000000000000000 前面多的一位是存不下的必然丢失
//	         00000000000000000000000000000000  - 0
//	return 0;
//}



//移位操作符
// <<左移位操作符
// >>右移位操作符
//只能在整数上操作，因为挪位置是操作补码


// <<左移位操作符

//int main()
//{
//	//正数
//	int a = 10;
//	//10二进制数字 00000000000000000000000000001010 -补码
//	//左边丢弃，右边补上
//	//            00000000000000000000000000010100 -相当与 *2  就等于20
//	int b = a << 1;//20
//	int c = a << 2;//40
//	int d = a << 3;//80
//	int e = a << 4;//160
//	printf("a == %d\n", a);
//	printf("b == %d\n", b);
//	printf("c == %d\n", c);
//	printf("d == %d\n", d);
//	printf("e == %d\n", e);
//	
//
//	//负数
//	int f = -10;
//	//10二进制数字 10000000000000000000000000001010 -原码
//	//            11111111111111111111111111110101 -反码
//	//            11111111111111111111111111110110 -补码
//	int g = f << 1;
//	//左边丢弃，右边补上
//	//            11111111111111111111111111101100 -补码 - g
//	//            10000000000000000000000000010100 -原码 - g  等于-20
//	printf("f == %d\n", f);
//	printf("g == %d\n", g);
//
//	return 0;
//}



// >>右移位操作符

// 右移有两种——逻辑和算术，这取决于编译器，vs编译器是采用算术右移。



//逻辑右移 
// 右移前：10000000000000000000000000001010  -10
// 右移后：01000000000000000000000000000101   他总是在前面补0，这显然会带来一定的错误
//
//算术右移
//右移前： 10000000000000000000000000001010
//右移后： 10000000000000000000000000010100  他会保留前面的符号位，在此基础上右移
//
//int main()
//{
//	int a = -10;
//	int b = a >> 1;
//	printf("a == %d\n", a);//-10
//	printf("b == %d\n", b);//-5
//	//算术右移和左移差不多但是是反过来 /2 
//	return 0;
//}
//
//注意：不要写出 a<<-1 这种逻辑代码 //error


//位操作符
// & - 按位与     && - 逻辑与（并且）
// | - 按位或     || - 逻辑或（或者）
// ^ - 按位异或   
// ~ - 按位取反

//int main()
//{
//	int a = 4;
//	int b = -7;
//	int c = a & b;
//	//使用补码进行按位与
//	//对应二进制位有0就是0，两个同时为1才是1。
//	//00000000000000000000000000000100 -    4的补码
//	//11111111111111111111111111111001 -  （-7）的补码
//	//00000000000000000000000000000000 -   0
//	printf("c == %d\n", c);
//	return 0;
//}



//int main()
//{
//	int a = 4;
//	int b = -7;
//	int c = a | b;
//	//使用补码进行按位或
//	//对应二进制位有1就是1，两个同时为0才是0。
//	//00000000000000000000000000000100 -    4的补码
//	//11111111111111111111111111111001 -  （-7）的补码
//	//11111111111111111111111111111101 -   补码
//	//取反 +1
//	//10000000000000000000000000000011 -   原码 - （-3）
//	printf("c == %d\n", c);// -3
//	return 0;
//}



//int main()
//{
//	int a = 4;
//	int b = -7;
//	int c = a ^ b;
//	//使用补码进行按位异或
//	//规则：相同为0，相异为1
//	//00000000000000000000000000000100 -    4的补码
//	//11111111111111111111111111111001 -  （-7）的补码
//	//11111111111111111111111111111101 -   补码
//	//10000000000000000000000000000011 -   原码
//	printf("c == %d\n", c);// -3
//	return 0;
//}


//int main()
//{
//	int a = 0;
//	int b = ~a;
//	//0000000000000000000000000000 -补码
//	//1111111111111111111111111111 -b中的补码
//	//取反 +1 
//	//1000000000000000000000000001  -- （-1）
//	printf("b == %d\n", b);// -1
//	return 0;
//}

//异或运算的特殊场景
// 相同为0，相异为1
// a^a = 0
// a^0 = a
//假设a为1
//二进制 001
//a ^ a 000 - 0
//a ^ 0 001 - 1
//支持交换律 即 a ^ b ^ a == a ^ a ^ b;
int main()
{
	int a = 3;
	int b = 5;
	printf("交换前：a = %d b = %d\n", a, b);
	a = a ^ b;
	b = a ^ b;//等价于 b = a ^ b ^ b; a ^ 0; a
	a = a ^ b;//等价于 a = (a ^ b) ^ a; 0 ^ b; b
	printf("交换后：a = %d b = %d\n", a, b);
	return 0;
}


//统计二进制数中1的个数
//我们知道十进制数统计每个各位数时是 %10 /10 
//那么二进制数可以通过 %2 /2 
//
//方法一：
//int count_of_bit(unsigned int m)
//{
//	int count = 0;
//	while (m)
//	{
//		if (m % 2 == 1)
//			count++;
//		m /= 2;
//	}
//	return count;
//}
//int main()
//{
//	int n = 0;
//	scanf("%d", &n);
//	int ret = count_of_bit(n);
//	printf("%d\n", ret);
//	return 0;
//}
//
//
//方法二：
//int count_of_bit(unsigned int m)
//{
//	int count = 0;
//	int i = 0;
//	for (i = 0; i < 32; i++)
//	{
//		if (((m >> i) & 1) == 1)
//			count++;
//	}
//	return count;
//}
//int main()
//{
//	int n = 0;
//	scanf("%d", &n);
//	int ret = count_of_bit(n);
//	printf("%d\n", ret);
//	return 0;
//}
//
//
//方法三：
//int count_of_bit(unsigned int m)
//{
//	int count = 0;
//	while (m)
//	{
//		count++;
//		m = m & (m - 1);
//	}
//	return count;
//}
//int main()
//{
//	int n = 0;
//	scanf("%d", &n);
//	int ret = count_of_bit(n);
//	printf("%d\n", ret);
//	return 0;
//}
//
//
//改动单独一个位置
//int main()
//{
//	int n = 13;
//	//00000000000000000000000000001101 改动前
//	//00000000000000000000000000010000 改动或
//	//00000000000000000000000000011101 改动后
//	//将n的第五位改成1
//	//1<<(5-1)
//	n = n | (1 << 4);
//	printf("%d\n", n);
//
//	//00000000000000000000000000011101 改动前
//	//11111111111111111111111111101111 改动与 
//	//   这个数字就是00000000000000000000000000010000按位取反
//	//00000000000000000000000000001101 改动后
//	//改回来
//	n = n & (~(1 << 4));
//	printf("%d\n", n);
//	return 0;
//}